﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using HeadCounter.Armourer.Base;
using HeadCounter.Armourer.Requesters;

namespace HeadCounter.Armourer
{
    public class ArmouryService: BackgroundWorker, IArmouryService
    {
        private readonly Dictionary<ReqeusterDataType, WebRequester> _requesters =
            new Dictionary<ReqeusterDataType, WebRequester>
                {
                    {ReqeusterDataType.Item, new Itemiser()},
                    {ReqeusterDataType.Character, new Census()}
                };

        public ArmouryService()
        {
            WorkerReportsProgress = true;
            WorkerSupportsCancellation = true;

            DoWork += Download;
        }

        public void RunArmouryServiceAsync()
        {
            if (!IsBusy)
            {
                ProgressChanged += ArmourerProgressChanged;
                RunWorkerCompleted += ArmourerRunWorkerCompleted;

                RunWorkerAsync();
            }
        }

        public bool IsWorking()
        {
            var result = false;
            _requesters.Values.ForEach(req =>
                                           {
                                               if (req.HasWork()) result = true;
                                           });

            return result;
        }


        public event EventHandler<ProgressChangedEventArgs> ArmouryServiceProgressChanged;

        public event EventHandler<RunWorkerCompletedEventArgs> ArmouryServiceCompleted;

        void ArmourerProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (ArmouryServiceProgressChanged != null)
            {
                ArmouryServiceProgressChanged(this as IArmouryService, e);
            }
        }

        void ArmourerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (ArmouryServiceCompleted != null)
            {
                ArmouryServiceCompleted(this as IArmouryService, e);
            }

            ProgressChanged -= ArmourerProgressChanged;
            RunWorkerCompleted -= ArmourerRunWorkerCompleted;
        }

        public void EnqueueGetItem(int itemId)
        {
            var itemiser = _requesters[ReqeusterDataType.Item] as Itemiser;
            itemiser.EnqueueGetItem(itemId);
        }

        public void EnqueueGetCharacter(WowRegion region, string realm, string name)
        {
            var census = _requesters[ReqeusterDataType.Character] as Census;
            census.EnqueueGetCharacter(new CharacterIdentity(region, realm, name));
        }

        void Download(object sender, DoWorkEventArgs e)
        {
            bool hasWork = true;

            while (hasWork)
            {
                hasWork = false;
                _requesters.Values.ForEach(req =>
                                        {
                                            if (req.HasWork())
                                            {
                                                var xml = req.RequestData(this);

                                                if (xml != null)
                                                {
                                                    if (req.GetDataType() == ReqeusterDataType.Item)
                                                    {
                                                        RaiseItemDownloadEvent(xml);
                                                    }
                                                    else if (req.GetDataType() == ReqeusterDataType.Character)
                                                    {
                                                        RaiseCharacterDownloadEvent(xml);
                                                    }
                                                }
                                                else
                                                {
                                                    ReportProgress(100, "Error downloading");
                                                    e.Result = 1;
                                                    return;
                                                }

                                                hasWork = true;
                                            }
                                        });    
            }

            ReportProgress(100, "Downloading completed");
            e.Result = 0;
        }

        private void RaiseItemDownloadEvent(XElement xml)
        {
            if (ItemDataDownloaded != null)
            {
                ItemDataDownloaded(this, new ItemDataDownloadedEventArgs(xml));
            }
        }

        private void RaiseCharacterDownloadEvent(XElement xml)
        {
            if (CharacterDownloaded != null)
            {
                CharacterDownloaded(this, new CharacterDataDownloadedEventArgs(xml));
            }
        }

        public event EventHandler<ItemDataDownloadedEventArgs> ItemDataDownloaded;
        public event EventHandler<CharacterDataDownloadedEventArgs> CharacterDownloaded;

        #region Helpers



        #endregion

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            DoWork -= Download;
        }

    }
}
